/*
 * $Id: file_open.c,v 1.1 2006-03-21 16:43:58 bacon Exp $
 */

#include <xp/sys/file.h>
#include <xp/bas/stdarg.h>
#include <xp/bas/locale.h>
#include <xp/bas/string.h>
#include <xp/bas/mstring.h>

#ifndef _WIN32
	#include <sys/stat.h>
	#include <fcntl.h>
#endif

xp_hnd_t xp_open (const xp_char_t* path, int flags, ...)
{
	xp_hnd_t handle;

#ifdef _WIN32

	DWORD desired_access = 0;
	DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
	DWORD creation_disposition = 0;
	DWORD attributes = FILE_ATTRIBUTE_NORMAL;
	DWORD file_type;
	
	if (flags & XP_OPEN_READ) desired_access |= GENERIC_READ;
	if (flags & XP_OPEN_WRITE) desired_access |= GENERIC_WRITE;

	if (flags & XP_OPEN_CREATE) 
	{
		creation_disposition = 
			(flags & XP_OPEN_EXCLUSIVE)? CREATE_NEW:
			(flags & XP_OPEN_TRUNCATE)? CREATE_ALWAYS: OPEN_ALWAYS;
	}
	else if (flags & XP_OPEN_TRUNCATE) {
		creation_disposition = TRUNCATE_EXISTING;
	}
	else creation_disposition = OPEN_EXISTING;

	/*if (flags & XP_FIO_SYNC) attributes |= FILE_FLAG_WRITE_THROUGH; */
	if (flags & XP_OPEN_NOSHAREREAD) share_mode |= ~FILE_SHARE_READ;
	if (flags & XP_OPEN_NOSHAREWRITE) share_mode |= ~FILE_SHARE_WRITE;

	handle = CreateFile (path, 
		desired_access, share_mode, XP_NULL, 
		creation_disposition, attributes, 0);
	if (handle == XP_HND_INVALID) return XP_HND_INVALID;

/* TODO: implement append
	fio->flags = 0;
	if (flags & XP_OPEN_APPEND) fio->flags |= XP_OPEN_APPEND;
*/
/* TODO: implement nonblock...
	if (flags & XP_OPEN_NONBLOCK) desired_access |= O_NONBLOCK;
*/

	file_type = GetFileType(handle);
	if (file_type == FILE_TYPE_UNKNOWN) 
	{
		CloseHandle (handle);
		return XP_HND_INVALID;
	}

	/*
	if (file_type == FILE_TYPE_CHAR) 
	else if (file_type == FILE_TYPE_PIPE)
	*/
	/* TODO: a lot more */

#else
	int desired_access = 0;
	xp_va_list arg;
	xp_mode_t mode;

	#ifdef XP_CHAR_IS_MCHAR
	const xp_mchar_t* path_mb;
	#else
	xp_mchar_t path_mb[XP_PATH_MAX + 1];
	#endif

	xp_va_start (arg, flags);
	if (xp_sizeof(xp_mode_t) < xp_sizeof(int))
		mode = xp_va_arg (arg, int);
	else
		mode = xp_va_arg (arg, xp_mode_t);
	xp_va_end (arg);

	#ifdef XP_CHAR_IS_MCHAR
	path_mb = path;
	#else
	if (xp_wcstomcs_strict (
		path, path_mb, xp_countof(path_mb)) == -1) return -1;
	#endif

	if (flags & XP_OPEN_READ) desired_access = O_RDONLY;
	if (flags & XP_OPEN_WRITE) 
	{
		if (desired_access == 0) desired_access |= O_WRONLY;
		else desired_access = O_RDWR;
	}

	if (flags & XP_OPEN_APPEND) desired_access |= O_APPEND;
	if (flags & XP_OPEN_CREATE) desired_access |= O_CREAT;
	if (flags & XP_OPEN_TRUNCATE) desired_access |= O_TRUNC;
	if (flags & XP_OPEN_EXCLUSIVE) desired_access |= O_EXCL;
	if (flags & XP_OPEN_NONBLOCK) desired_access |= O_NONBLOCK;

	handle = open (path_mb, desired_access, mode);
#endif

	return handle;
}

